package com.yifeng.repo.micro.service.server.engine.generate;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.sql.Types;
import java.util.Collections;

/**
 * Created by daibing on 2023/6/19.
 */
public class MybatisPlusGenerator {
    private static final String SERVER = "server";
    private static final String INTERNAL = "internal";

    public static void mybatisPlusGenerateCode(MybatisPlusGeneratorConf conf) throws UnsupportedEncodingException {
        String resourceName = getResourceName(conf);
        FastAutoGenerator.create(conf.getUrl(), conf.getUsername(), conf.getPassword())
                .globalConfig(builder -> {
                    builder.author(conf.getAuthor())
                            .outputDir(conf.getProjectAbsoluteDir()
                                    + File.separator + "src"
                                    + File.separator + "main"
                                    + File.separator + "java")
                            .disableOpenDir()
                            .dateType(DateType.TIME_PACK);
                    if (conf.isDisableServiceInterface()) {
                        builder.disableServiceInterface();
                    }
                })
                .dataSourceConfig(builder -> builder
                            .typeConvertHandler(((globalConfig, typeRegistry, metaInfo) -> {
                                boolean typeMatched = metaInfo.getJdbcType().TYPE_CODE == Types.TINYINT
                                        || metaInfo.getJdbcType().TYPE_CODE == Types.BIT;
                                boolean bodyMatched = metaInfo.getLength() == 1
                                        || metaInfo.toString().contains("columnName=is_")
                                        || metaInfo.toString().contains("columnName='is_");
                                if (typeMatched && bodyMatched) {
                                    return DbColumnType.BOOLEAN;
                                } else {
                                    return typeRegistry.getColumnType(metaInfo);
                                }
                            })))
                .packageConfig(builder -> {
                            builder.moduleName(conf.getModuleName())
                                    .parent(conf.getParent())
                                    .mapper("dao")
                                    .pathInfo(Collections.singletonMap(OutputFile.xml, conf.getProjectAbsoluteDir()
                                            + File.separator + "src"
                                            + File.separator + "main"
                                            + File.separator + "resources"
                                            + File.separator + "mybatis"
                                            + File.separator + resourceName));
                            if (conf.isDisableServiceInterface()) {
                                builder.serviceImpl("service");
                            }
                        }
                )
                .strategyConfig(builder -> {
                            builder.addTablePrefix(conf.getTablePrefixList()).addInclude(conf.getIncludes())
                                    .controllerBuilder().enableFileOverride().enableRestStyle()
                                    .serviceBuilder().enableFileOverride().formatServiceFileName("%sService")
                                    .entityBuilder().enableFileOverride().enableLombok().enableChainModel()
                                        .idType(IdType.ASSIGN_ID).disableSerialVersionUID().formatFileName("%sEntity")
                                        .logicDeleteColumnName(conf.getLogicDeleteColumnName())
                                        .logicDeletePropertyName(conf.getLogicDeleteColumnName().replace("is_", ""))
                                        .naming(NamingStrategy.underline_to_camel).columnNaming(NamingStrategy.underline_to_camel)
                                    .mapperBuilder().enableFileOverride().enableBaseResultMap().enableBaseColumnList();
                            if (conf.isEnableRemoveIsPrefix()) {
                                builder.entityBuilder().enableRemoveIsPrefix();
                            }
                            if (conf.isDisableServiceInterface()) {
                                builder.serviceBuilder().formatServiceImplFileName("%sService");
                            }
                        }
                )
                .templateEngine(new MybatisPlusFreemarkerTemplateEngine(conf.getProjectAbsoluteDir(), resourceName, conf.isMappingStartByModuleName(),
                        conf.isEnableDynamicSource(), conf.isEnableGenerateUml()))
                .execute();
    }

    private static String getResourceName(MybatisPlusGeneratorConf conf) {
        // 模块名称不是internal，就直接用模块名称作为资源名称
        if (!INTERNAL.equalsIgnoreCase(conf.getModuleName())) {
            return conf.getModuleName();
        }
        // parent包路径是server结尾，就是未指定其他子包，也直接用模块名称作为资源名称
        if (conf.getParent().endsWith(SERVER)) {
            return conf.getModuleName();
        }
        // 默认使用parent包路径的最后一个包路径作为资源名称
        return conf.getParent().substring(conf.getParent().lastIndexOf(".") + 1);
    }

}
